﻿using System;
using Hive.Core.Common.Shell;

namespace Hive.Core.Model.Commands
{
    /// <summary>
    /// A command encapsulates the parameters and behavior of a requested operation.
    /// </summary>
    public abstract class Command
    {
        /// <summary>
        /// Executes the command.
        /// </summary>
        /// <param name="hiveManager">The hive manager.</param>
        /// <param name="shell">The shell.</param>
        /// <returns>The command exit code.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="hiveManager"/>
        /// or <paramref name="shell"/> is null.</exception>
        public CommandExitCode Execute(IHiveManager hiveManager, IShell shell)
        {
            if (hiveManager == null)
                throw new ArgumentNullException("hiveManager");
            if (shell == null)
                throw new ArgumentNullException("shell");

            try
            {
                return ExecuteImpl(hiveManager, shell);
            }
            catch (OperationCanceledException ex)
            {
                shell.Echo(MessageSeverity.Warning, string.Format("The operation was canceled.\n{0}", ex.Message));
                return CommandExitCode.Canceled;
            }
            catch (Exception ex)
            {
                shell.EchoException("The command failed.", ex);
                return CommandExitCode.Exception;
            }
        }

        /// <summary>
        /// Executes the command.
        /// </summary>
        /// <remarks>
        /// <para>
        /// If an exception is thrown by this method, it will be captured and logged by
        /// <see cref="Execute" />.  An exception of type <see cref="OperationCanceledException" />
        /// will be reported as <see cref="CommandExitCode.Canceled" />.
        /// </para>
        /// </remarks>
        /// <param name="hiveManager">The hive manager, not null.</param>
        /// <param name="shell">The shell, not null.</param>
        /// <returns>The command exit code.</returns>
        protected abstract CommandExitCode ExecuteImpl(IHiveManager hiveManager, IShell shell);
    }
}
